/**
 * @file   type_traits.hpp
 * @author wolfhead <wolfhead@wolfhead-laptop>
 * @date   Tue Sep  6 16:40:33 2011
 * 
 * @brief  
 * 
 * 
 */

#ifndef ACAPELLA_TRAITS_TYPE_TRAITS_HPP
#define ACAPELLA_TRAITS_TYPE_TRAITS_HPP

#include "../tools.hpp"
#include "../typelist/typelist.hpp"

namespace acapella
{
namespace traits
{

template<typename T>
class TypeTraits
{
private:
    typedef TYPELIST_4(
        unsigned char, unsigned short int, 
        unsigned int,  unsigned long int) UnsignedInt;

    typedef TYPELIST_4(
        signed char, short int,
        int, long int) SignedInt;

    typedef TYPELIST_3(float, double, long double) Float;
    
    typedef TYPELIST_3(bool, char, wchar_t) OtherInt;

    /**
     * IsPointerType determine whether the type is a pointer
     */
    template <typename U>
    struct IsPointerTraits
    {
        enum {result = false};
    };

    template <typename U>
    struct IsPointerTraits<U *>
    {
        enum {result = true};
    };

   /**
    * IsMemberPointerTraits determine whether the type is a member pointer
    */
    template <typename U>
    struct IsMemberPointerTraits
    {
        enum {result = false};
    };

    template <typename U, typename V>
    struct IsMemberPointerTraits<U V::*>
    {
        enum {result = true};
    };

   /**
    * IsReferenceTraits determine whether a type is reference type
    */
    template <typename U>
    struct IsReferenceTraits
    {
        enum {result = false};
    };

    template <typename U>
    struct IsReferenceTraits<U &>
    {
        enum {result = true};
    };

    /**
     * IsConstTraits determine whether a type is const qualified
     */
    template <typename U>
    struct IsConstTraits
    {
        enum {result = false};
    };

    template <typename U>
    struct IsConstTraits<const U>
    {
        enum {result = true};
    };

   /**
    * IsVolatileTraits determine whether a type is volatile qualified
    */
    template <typename U>
    struct IsVolatileTraits
    {
        enum {result = false};
    };

    template <typename U>
    struct IsVolatileTraits<volatile U>
    {
        enum {result = true};
    };

   /**
    * get the pointee type of a pointer
    */
    template <typename U>
    struct PointeeTypeTraits
    {
        typedef U type;
    };

    template <typename U>
    struct PointeeTypeTraits<U *>
    {
        typedef U type;
    };

    /**
     * ReferencedTraits get the referenced type of a reference
     * if the type is not a reference type, then then referenced type is itself
     */
    template <typename U>
    struct ReferencedTypeTraits
    {
        typedef U type;
    };

    template <typename U>
    struct ReferencedTypeTraits<U &>
    {
        typedef U type;
    };

    /**
     * ReferencedTraits get the reference type of type
     */
    template <typename U, typename Stub>
    struct ReferenceTypeTraits
    {
        typedef U & type;
    };

    template <typename U, typename Stub>
    struct ReferenceTypeTraits<U &, Stub>
    {
        typedef U & type;
    };

    template <typename Stub>
    struct ReferenceTypeTraits<void, Stub>
    {
        typedef void type;
    };

    template <typename Stub>
    struct ReferenceTypeTraits<const void, Stub>
    {
        typedef void type;
    };

    template <typename Stub>
    struct ReferenceTypeTraits<volatile void, Stub>
    {
        typedef void type;
    };

    template <typename Stub>
    struct ReferenceTypeTraits<volatile const void, Stub>
    {
        typedef void type;
    };


    /**
     * NonConstTypeTraits remove the const qualifier of a type
     */
    template <typename U>
    struct NonConstTypeTraits
    {
        typedef U type;
    };

    template <typename U>
    struct NonConstTypeTraits<const U>
    {
        typedef U type;
    };

    /**
     * NonVolatileTypeTraits remove the const qualifier of a type
     */
    template <typename U>
    struct NonVolatileTypeTraits
    {
        typedef U type;
    };

    template <typename U>
    struct NonVolatileTypeTraits<volatile U>
    {
        typedef U type;
    };

    struct Stub{};

public:
    enum {isPointer = IsPointerTraits<T>::result};

    enum {isMemberPointer = IsMemberPointerTraits<T>::result};

    enum {isReference = IsReferenceTraits<T>::result};

    enum {isConst = IsConstTraits<T>::result};

    enum {isVolatile = IsVolatileTraits<T>::result};
/*
    enum {isStdVoid = 
          Conversion<T, void>::same || 
          Conversion<T, const void>::same ||
          Conversion<T, volatile void>::same ||
          Conversion<T, const volatile void>::same};
*/
    enum {isStdUnsignedInt = TL::IndexOf<UnsignedInt, T>::value >= 0};

    enum {isStdSignedInt = TL::IndexOf<SignedInt, T>::value >= 0};

    enum {isStdIntergarl = 
          isStdSignedInt || 
          isStdUnsignedInt || 
          TL::IndexOf<OtherInt, T>::value >= 0};

    enum {isStdFloat = TL::IndexOf<Float, T>::value >= 0};

    enum {isStdArith = isStdIntergarl || isStdFloat};

    enum {isStdFundamental = isStdArith || false};

    typedef T SelfType;

    typedef typename PointeeTypeTraits<T>::type PointeeType;

    typedef typename ReferencedTypeTraits<T>::type ReferencedType;

    typedef typename ReferenceTypeTraits<T, Stub>::type ReferenceType;

    typedef typename TypeTraits<PointeeType>::ReferencedType ElementType;

    typedef typename NonConstTypeTraits<T>::type NonConstType;

    typedef typename NonVolatileTypeTraits<T>::type NonVolatileType;

    typedef typename NonConstTypeTraits<NonVolatileType>::type NonQualifiedType;

    typedef typename Select<isStdFundamental || isMemberPointer || isPointer,
                            T, ReferenceType>::type ParameterType;

    typedef const typename Select<isStdFundamental || isMemberPointer || isPointer,
                            T, ReferenceType>::type ConstParameterType;
};





}//NAMESPACE traits
}//namespace acapella

#endif
